home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Sherlock 2.0
/
DevLibSrc
/
Main_DevLib
/
LIBlog.c
< prev
next >
Wrap
Text File
|
1996-02-09
|
11KB
|
533 lines
/*
devlib: log file handling routines.
source: LIBlog.c
started: December 14, 1990
version:
February 5, 1996.
Added support for Symantec C.
October 28, 1995.
Removed log_abort routine.
This clarifies where SysBeep is called.
September 25, 1995.
Added support for Code Warrior.
August 31, 1991.
Write to stderr instead of stdout, even for Tuple C.
July 16, 1994.
Added log_clanks.
December 13, 1993.
Initialize log_newlines to 1 so an initial cnl() does nothing.
*/
#include <LIBlib.h>
#include <LIBend.h>
#include <LIBlog.h>
#include <LIBmem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
LOG_DOCUMENT_CREATOR sets the "Creator" field for log files.
Single quotes must be used.
'????' specifies a generic document.
'KAHL' specifies a LightSpeed C document.
'MMCC' specifies a Code Warrior document.
#define USE_STD_IO if you want to use ANSI Standard I/O.
The *only* reason for having Mac-specific routines in this file
is so that they set the document's "creator" field.
*/
#if defined(THINK_C) || defined(SYMANTEC_C) || defined(__MWEKRS__)
#undef USE_STD_IO /* Use Mac routines: can set 'creator' field. */
#define LOG_DOCUMENT_CREATOR 'KAHL'
#include <Files.h>
#include <StandardFile.h>
#include <string.h>
#include <pascal.h>
#include <mac_gui.h>
#elif defined(__MWERKS__)
#undef USE_STD_IO /* Use Mac routines: can set 'creator' field. */
#define LOG_DOCUMENT_CREATOR 'MMCC'
#include <Files.h>
#include <StandardFile.h>
#include <string.h>
#include <mac_gui.h>
#elif defined(applec)
#undef USE_STD_IO /* Use Mac routines: can set 'creator' field. */
#define LOG_DOCUMENT_CREATOR '????'
#define PtoCstr(a) p2cstr(a)
#define CtoPstr(a) c2pstr(a)
#include <Errors.h>
#include <Files.h>
#include <Packages.h>
#include <Strings.h>
#include <String.h>
#else
#define USE_STD_IO /* Use ANSI routines: can't set 'creator' field. */
#define LOG_DOCUMENT_CREATOR '????'
#include <stdio.h>
#include <string.h>
#endif
/*
Define local variables.
*/
static int log_count = 0; /* Buffer count. */
static int log_newlines = 1; /* Consecutive newline count. */
static char * log_fileName = NULL; /* Trace file name. */
static int log_open_flag = FALSE; /* Logging enable flag. */
static short log_vRefNum; /* volume reference number. */
static FILE * log_file = NULL; /* File info. */
#define LOG_BUF_COUNT_MAX 150 /* Newlines will be inserted after this many chars. */
static char *log_buffer = NULL; /* Output line buffer. */
/*
Function prototypes of internal routines.
*/
static void log_error (char * message, char * fileName, int err_code);
static void log_write (char * buffer, long count);
/*
Close the log file if it is open.
*/
void
log_close(void)
{
if (log_open_flag) {
ecnl(); es("closing log file: "); es(log_fileName); enl();
/* Close the file. */
#ifdef USE_STD_IO
fclose(log_file);
#else
FSClose(log_vRefNum);
FlushVol(0L, log_vRefNum);
#endif
/* Mark the file as closed. */
log_open_flag = FALSE;
}
}
/*
Conditional blanks.
Output blanks to the indicated column.
*/
void
log_cblanks(short n)
{
n = n-log_count;
n = min(n, LOG_BUF_COUNT_MAX);
while (n-- > 0) {
log_cout(' ');
}
}
/*
Conditional new line.
Output a newline if there are characters already in the line.
*/
void
log_cnl(void)
{
if (log_newlines == 0) {
log_cout('\n');
}
}
/*
Insure at least n consecutive newlines.
*/
void
log_cnls(short n)
{
int i;
for (i = n - log_newlines; i > 0; i--) {
log_cout('\n');
}
}
/*
Output a character to the log window, the log file, or both.
All es output eventually goes through this routine.
Keep track of the number of consecutive newlines for log_cnl and log_cnls.
*/
void
log_cout(char c)
{
int temp_count = 0;
/* Bug fix: 5/18/92 */
if (log_buffer == NULL) {
log_buffer = lib_calloc( (size_t) 1, LOG_BUF_COUNT_MAX);
if (log_buffer == NULL) {
end_abort();
}
log_count = 0;
}
/* Use 4-space tabs. */
if (c == '\t') {
register int pad = 4 - (log_count % 4);
register int i;
for (i = 0; i < pad && log_count < LOG_BUF_COUNT_MAX-10; i++) {
log_buffer[log_count++] = ' ';
}
log_newlines = 0;
return;
}
/* Ignore unprintable characters. */
if (c < 32 && c != '\n') {
log_newlines = 0;
return;
}
/*
Buffer all characters until a newline arrives.
This buffering greatly speeds up file and window output.
*/
if (c != '\n') {
/* Add the character. */
log_buffer[log_count++] = c;
/*
6/3/94: Add a newline if the buffer is nearly full.
This allows a smaller buffer and makes the log easier to read.
*/
if (log_count < LOG_BUF_COUNT_MAX-10) {
log_newlines = 0;
return;
}
else {
c = '\n';
}
}
/* Finish off the buffer. */
log_newlines++;
/* The Mac-specific translation from '\n' to '\r' is handled in slw_write. */
log_buffer[log_count++] = '\n';
log_buffer[log_count] = '\0';
/* Kludge: save log_count so it can be restored later. */
temp_count = log_count;
#ifdef SHERLOCK
sl_ovb();
#endif
/* Write the line to the log window or to standard error. */
#if defined(THINK_C) || defined(SYMANTEC_C) || defined(__MWERKS__)
/*
Reset log_count before calling slw_write so we
won't print the line twice if slw_write calls end_quit.
*/
#if 0 /* try mixed windows. */
if (lib_stderr_flag) {
log_count = 0;
fwrite(&log_buffer[0],1,temp_count,stderr);
}
else {
log_count = 0;
slw_write(&log_buffer[0], temp_count);
}
#endif
log_count = 0;
slw_write(&log_buffer[0], temp_count);
#else
{
register char * s;
register char c;
for (s = &log_buffer[0]; c = *s; s++) {
/* 5/26/93: Use stderr in MPW so that I/O is not buffered. */
#ifdef applec
/*
Interchange '\r' and '\n'.
The standard file routines do this automatically.
Note that MPW C interchanges these at *compile*
time so this does not have to be done at run time.
*/
if (c == '\r') {
c = '\n';
}
else if (c == '\n') {
c = '\r';
}
fputc(c, stderr);
#else
/* A standard OS should get this right. */
#if 0
putchar(*s);
#endif
fputc(c, stderr);
#endif
}
}
#endif
/*
Write the completed line to the log file if open.
Write this *after* writing to the window so
log_write is free to interchange '\n' and '\r'.
*/
if (log_open_flag) {
/* Restore the proper count now that we know end_quit has not been called. */
log_count = temp_count;
log_write(&log_buffer[0], log_count);
}
/* Clear out the buffer. */
log_count = 0;
#ifdef SHERLOCK
sl_ovx();
#endif
}
/*
Give an error message.
*/
static void
log_error(char * message, char * fileName, int err_code)
{
es(message); eblank();
es(fileName); eblank();
elp(); log_errout(err_code); erpnl();
}
/*
Return TRUE if the log file is open.
*/
int
log_isopen(void)
{
return log_open_flag;
}
/*
Close the log file if it is open, then
open the named file for writing, erasing it if it exists.
The *only* reason for using Mac-specific routines here is that
Create sets the document's "creator" field.
*/
void
log_open(char * fileName)
{
log_open_vRefNum(0, fileName);
}
void
log_open_vRefNum(short vRefNum, char * fileName)
{
#ifndef USE_STD_IO
OSErr err; /* File error code. */
Str255 pFileName; /* Pascal File Name. */
#endif
if (fileName == (char *) 0 || fileName[0] == '\0') {
/* This should never happen. */
es("log_open: null file name\n");
return;
}
/*
Close a file if it is open.
This can happen if >file is chosen from the options menu.
*/
if (log_open_flag) {
ecnl(); es("Closing log file: "); es(log_fileName); enl();
log_close();
}
#ifdef USE_STD_IO
log_file = fopen(fileName, "w");
if (log_file == NULL) {
es("Can not open log file: "); es(fileName); enl();
return;
}
#else
strcpy( (char *) &pFileName, fileName);
CtoPstr( (char *) &pFileName);
/* See if the file exists. */
err = FSOpen((pstring) &pFileName, vRefNum, &log_vRefNum);
if (err != noErr && err != fnfErr) {
log_cnl();
log_error("Can not open", fileName, err);
return;
}
if (err == noErr) {
/* File is open. Just erase it. */
SetEOF(log_vRefNum, 0L);
}
else {
/* Create the file. */
err = Create((pstring) pFileName, vRefNum,
(OSType) LOG_DOCUMENT_CREATOR, (OSType) 'TEXT');
if (err != noErr) {
log_cnl();
log_error("Can not create log file: ", fileName, err);
return;
}
/* Open the file and set log_vRefNum. */
err = FSOpen(pFileName, vRefNum, &log_vRefNum);
if (err != noErr) {
log_cnl();
log_error("Can not open log file: ", fileName, err);
return;
}
}
#endif
/*
We have opened the file successfully.
Set the global file name, and file flag.
*/
if (log_fileName == NULL) {
log_fileName = lib_calloc( (size_t) 1, MAX_LOG_FILE_NAME);
}
/* 5/13/93: Make sure we don't over-write the buffer. */
strncpy(log_fileName, fileName, MAX_LOG_FILE_NAME-2);
log_fileName[MAX_LOG_FILE_NAME-2]= '\0';
log_open_flag = TRUE;
/* After this point, traces go to the log file. */
ecnl(); es("Opening log file: "); es(fileName); enl();
return;
}
/*
Output a string to the standard output stream.
Keep track of consecutive newlines.
*/
void
log_sout(char * s)
{
while (*s) {
log_cout(*s++);
}
}
/*
Write the buffer and to the file.
The caller is responsible for saving and restoring the grafPtr.
*/
static void
log_write(char * buffer, long length)
{
#ifdef USE_STD_IO
long count = 0;
/* 7/28/93: Handle this translation here for the perverted MPW library. */
#ifdef applec
if (length && buffer[length-1] == '\n') {
buffer[length-1] = '\r';
}
#endif
count = fwrite(buffer, 1, length, log_file);
if (count < 0) {
es("Error writing to "); es(log_fileName); enl();
}
#else
OSErr err; /* File error code. */
long count=length;
/* 5/13/93: Handle this translation here. */
if (count && buffer[count-1] == '\n') {
buffer[count-1] = '\r';
}
err = FSWrite(log_vRefNum, &count, (Ptr) buffer);
if (err != noErr) {
/*
Close the file before creating more output!
Don't call log_close: it produces output.
*/
FSClose(log_vRefNum);
log_open_flag = FALSE;
log_cnl();
log_error("Error writing to", log_fileName, err);
}
#endif
/* Check for truncated lines. */
if (count != length) {
log_cnl(); es("Write to "); es(log_fileName); es(" truncated\n");
}
}
/*
Output a descriptive message corresponding to a file error code.
*/
void
log_errout(int OSErrCode)
{
char buffer [CVT_BUF_SIZE];
es(cvt_file_error(buffer, CVT_BUF_SIZE, OSErrCode));
}